/*
 * draw.c
 *
 *  Created on: 21/12/2010
 *      Author: fanl
 */

#include "fdraw.h"
UNS_16 color24to565(UNS_32 in)
{
	UNS_16 out;
	out =  (in & 0x00F80000) >> 8;
	out |= (in & 0x0000FC00) >> 5;
	out |= (in & 0x000000F8) >> 3;
	return out;
}

void LCD_draw_box(UNS_32 page, UNS_32 bpp, UNS_32 color, UNS_32 x1, UNS_32 x2, UNS_32 y1, UNS_32 y2)
{
	UNS_16 *p16start = (UNS_16 *)(LCD_VRAM_BASE_ADDR + (page * C_LCD_PAGE_SIZE));
	UNS_16 *p16;
	UNS_32 i,j;

	switch(bpp)
	{
	case 16:
		color = color24to565(color);
		p16start += x1 + y1 * C_LCD_H_SIZE; //Start corner
		for(j=0; j<(y2-y1); j++)
		{
			p16 = p16start + j*C_LCD_H_SIZE;
			for(i=0; i<(x2-x1); i++ )
			{
				*p16++ = color & 0xFFFF;
			}
		}
		break;
	default:
		break;
	}
}

void LCD_draw_dot(UNS_32 page, UNS_32 bpp, UNS_32 color, UNS_32 x, UNS_32 y, UNS_8 type)
{
	UNS_16 *p16 = (UNS_16 *)(LCD_VRAM_BASE_ADDR + (page * C_LCD_PAGE_SIZE));
	int i;

	switch(type)
	{
	case 0:
		switch(bpp)
		{
		case 16:
			color = color24to565(color);
			p16++;

			p16 += x + y * C_LCD_H_SIZE;

			*p16 = color & 0xFFFF;
			break;
		default:
			break;
		}
		break;

	case 1:
		switch(bpp)
		{
		case 16:
			p16 += (x-1) + (y-3) * C_LCD_H_SIZE;
			*p16++ = color; *p16++ = color;
			p16 += C_LCD_H_SIZE;
			*p16-- = color; *p16-- = color; *p16-- = color; *p16-- = color;
			p16 += C_LCD_H_SIZE;
			*p16++ = color; *p16++ = color; *p16++ = color; *p16++ = color; *p16++ = color; *p16++ = color;
			p16 += C_LCD_H_SIZE;
			*p16-- = color; *p16-- = color; *p16-- = color; *p16-- = color; *p16-- = color; *p16-- = color; *p16-- = color; *p16 = color;
			p16 += C_LCD_H_SIZE;
			*p16++ = color; *p16++ = color; *p16++ = color; *p16++ = color; *p16++ = color; *p16++ = color; *p16++ = color; *p16 = color;
			p16 += C_LCD_H_SIZE;
			*--p16 = color; *--p16 = color; *--p16 = color; *--p16 = color; *--p16 = color; *--p16 = color;
			p16 += C_LCD_H_SIZE;
			*++p16 = color; *++p16 = color; *++p16 = color; *++p16 = color;
			p16 += C_LCD_H_SIZE;
			*--p16 = color; *--p16 = color;
			break;
		default:
			break;
		}
		break;

	default:
		break;
	}
}

int abs(int a)
{
	if(a<0) return -a;
	return a;
}

void LCD_draw_line(UNS_32 page, UNS_32 bpp, UNS_32 color, UNS_32 x0, UNS_32 x1, UNS_32 y0, UNS_32 y1, UNS_8 type)
{
	int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
	int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1;
	int err = (dx>dy ? dx : -dy)/2, e2;

	for(;;)
	{
		LCD_draw_dot(page, bpp, color, x0, y0, type);
		if (x0==x1 && y0==y1) break;
		e2 = err;
		if (e2 >-dx) { err -= dy; x0 += sx; }
		if (e2 < dy) { err += dx; y0 += sy; }
	}
}

void LCD_draw_circle(UNS_32 page, UNS_32 bpp, UNS_32 color, UNS_32 x0,UNS_32 y0, UNS_32 radius, UNS_8 type)
{
  int f = 1 - radius;
  int ddF_x = 1;
  int ddF_y = -2 * radius;
  int x = 0;
  int y = radius;

  LCD_draw_dot(page, bpp, color, x0, y0 + radius, type);
  LCD_draw_dot(page, bpp, color, x0, y0 - radius, type);
  LCD_draw_dot(page, bpp, color, x0 + radius, y0 , type);
  LCD_draw_dot(page, bpp, color, x0 - radius, y0, type);

  while(x < y)
  {
    // ddF_x == 2 * x + 1;
    // ddF_y == -2 * y;
    // f == x*x + y*y - radius*radius + 2*x - y + 1;
    if(f >= 0)
    {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;
    LCD_draw_dot(page, bpp, color, x0 + x, y0 + y, type);
    LCD_draw_dot(page, bpp, color, x0 - x, y0 + y, type);
    LCD_draw_dot(page, bpp, color, x0 + x, y0 - y, type);
    LCD_draw_dot(page, bpp, color, x0 - x, y0 - y, type);
    LCD_draw_dot(page, bpp, color, x0 + y, y0 + x, type);
    LCD_draw_dot(page, bpp, color, x0 - y, y0 + x, type);
    LCD_draw_dot(page, bpp, color, x0 + y, y0 - x, type);
    LCD_draw_dot(page, bpp, color, x0 - y, y0 - x, type);
  }
}

void LCD_clear_page(UNS_32 page, UNS_32 bpp, UNS_32 color)
{
	UNS_16 *p16 = (UNS_16 *)(LCD_VRAM_BASE_ADDR + (page * C_LCD_PAGE_SIZE));
	int i;

	switch(bpp)
	{
	case 16:
		color = color24to565(color);
		for(i=0; i<C_LCD_H_SIZE*C_LCD_V_SIZE; i++) *p16++ = color & 0xFFFF;
		break;
	default:
		break;
	}
}
